/*
 * @Author: 张宇飞
 * @Date: 2020-03-02 16:30:58
 * @LastEditors: 张宇飞
 * @LastEditTime: 2020-03-02 17:45:25
 * @Description: 自旋锁和互斥锁的大部分使用场景类似。但是互斥锁是进入休眠。
 * 自旋锁则是在用户态空转。所以不适合长时间运行
 * @Email: zhangyufei49@163.com
 */
#define _GNU_SOURCE

#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <unistd.h>

static pthread_spinlock_t glock;

static void* a(void* arg) {
    fprintf(stderr, "thread a start\n");
    pthread_spin_lock(&glock);
    fprintf(stderr, "thread a has got spin lock\n");
    sleep(5);
    pthread_spin_unlock(&glock);
    fprintf(stderr, "thread a released spin lock and exit\n");
    return NULL;
}

static void* b(void* arg) {
    sleep(1);
    fprintf(stderr, "thread b start, and blocked here\n");
    pthread_spin_lock(&glock);
    fprintf(stderr, "thread b has got spin lock\n");
    sleep(8);
    pthread_spin_unlock(&glock);
    fprintf(stderr, "thread b released spin lock and exit\n");
    return NULL;
}

static int set_affinity(int core_id, pthread_t pid) {
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(core_id, &cpuset);
    return pthread_setaffinity_np(pid, sizeof(cpuset), &cpuset);
}

int main(int argc, char const* argv[]) {
    // 判定 cpu 核心数量
    int ncpus = get_nprocs();
    if (ncpus < 2) {
        fprintf(stderr,
                "这个例子的演示需要当前环境有至少两个可用的 CPU 核心\n");
        return -1;
    }
    pid_t pid = getpid();
    printf(
        "请观察进程 %d 在第 2 个 cpu 的占用率。它将在线程 a 退出前都是 "
        "100%%\n",
        pid);

    pthread_spin_init(&glock, 0);
    pthread_t pid_a, pid_b;
    pthread_create(&pid_a, NULL, a, NULL);
    pthread_create(&pid_b, NULL, b, NULL);
    // 绑定线程到 cpu
    assert(0 == set_affinity(0, pid_a));
    assert(0 == set_affinity(1, pid_b));

    pthread_join(pid_a, NULL);
    pthread_join(pid_b, NULL);
    pthread_spin_destroy(&glock);
    return 0;
}
